from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import serializers
from user.models import UserModel, ThirdPartyAuth
from django_redis import get_redis_connection
import re
from rest_framework.serializers import ModelSerializer

# 用户
class SfUserSerializer(ModelSerializer):
    class Meta:
        model = UserModel
        fields = ['id', 'username', 'phone', 'password']

# 三方登录
class ThirdPartyAuthSerializer(ModelSerializer):

    class Meta:
        model = ThirdPartyAuth
        fields = ['id', 'user', 'type', 'uid']

# ============================================ 签发token ============================================

class CoustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    # 自定义序列化器，实现自定义载荷信息得添加
    @classmethod
    def get_token(cls, user):
        # 根据用户，获取token
        token = super().get_token(user)
        token['id'] = str(user.id)
        # token['username'] = str(user.username)
        # token['avatar'] = str(user.avatar)
        token['phone'] = str(user.phone)
        token['email'] = str(user.email)
        # token['money'] = str(user.money)
        # token['credit'] = str(user.credit)
        return token

# ============================================ 手机号注册 ============================================

class RegisterSerializer(serializers.ModelSerializer):
    re_password = serializers.CharField(required=True, write_only=True, min_length=6, max_length=16)
    sms_code = serializers.CharField(required=True, write_only=True, min_length=4, max_length=8)

    role = serializers.ChoiceField(choices=UserModel.CHOICES, required=False, default='user')

    # 仅在序列化中使用，用于注册成功后，返回登录令牌 ；toekn  refresh
    token = serializers.CharField(read_only=True)
    refresh = serializers.CharField(read_only=True)

    class Meta():
        model = UserModel
        fields = ['phone', 'role', 'password', 're_password', 'sms_code', 'token', 'refresh']
        extra_kwargs = {
            "phone":{
                "required":True,
                "write_only":True,
            },
            "password":{
                "required": True,
                "write_only": True,
                "min_length":6,
                "max_length":16
            }
        }
    def validate(self, attrs):
        # 自定义任意校验规则
        # 校验传递数据，是否满足业务需求
        phone = attrs.get('phone',None)
        # 判断手机号是否满足规则
        if not re.match(r'^1[3-9]\d{9}$',phone):
            raise serializers.ValidationError(detail="手机号格式错误",code="phone")
        print('-------手机号校验通过--------')

        # 校验两次密码是否相同
        password = attrs.get('password')
        re_password = attrs.get('re_password')

        if password != re_password:
            raise serializers.ValidationError(detail="两次密码不一致,请重新输入密码",code="password")

        print('-------密码校验通过,两次密码相同---------')

        # -------------------redis:短信验证码------------------
        sms_code = attrs.get('sms_code')
        # 验证码操作 稍后开发
        # 默认验证码是正确
        redis = get_redis_connection('sms_code')
        code = redis.get(f'sms_{phone}')
        # redis中获取到的数据类型都是字节类型
        print('redis中保存的短信验证码:',code)
        if code == None:
            raise serializers.ValidationError(detail='验证码过期,请重新获取验证码',code="sms_code")
        # if code.decode() != sms_code:
        if code != sms_code:
            raise serializers.ValidationError(detail='验证码错误,请重新输入',code='sms_code')

        redis.delete(f'sms_{phone}')

        # -------------------redis:短信验证码------------------

        # 程序健壮性考虑
        # 判断一次用户是否存在
        try:
            UserModel.objects.get(phone__exact=phone)
            raise serializers.ValidationError(detail='用户已经存在了...请登录',code='phone')
        except UserModel.DoesNotExist:
            print('注册信息数据不存在,可以正常执行注册操作.所有数据校验通过')

        # 校验通过，删除不必要得字段
        attrs.pop('re_password')

        return attrs
    def create(self, validated_data):
        phone = validated_data.get('phone')
        password = validated_data.get('password')
        role = validated_data.get('role', 'user')
        # 注册新用户，初始化用户信息
        users = UserModel.objects.create_user(
            phone = phone,
            password = password,
            # 随机给默认用户名 ,根据需求随机生成
            username = phone,
            role = role,
            # money = 0.0,
            # credit = 0,
            avatar = "avatar/2024/avatar.jpg"
        )
        # 返回数据
        # token   refresh
        print('------用户创建成功,手动签发token----------')
        # 手动签发token
        refresh = CoustomTokenObtainPairSerializer.get_token(user=users)

        users.token = str(refresh['access_token'])
        users.refresh_token = str(refresh['refresh'])
        users.save()
        
        return users

# ============================================ 邮箱注册 ============================================

class EmailSerializer(serializers.ModelSerializer):
    re_password = serializers.CharField(required=True,write_only=True,min_length=6,max_length=16)
    role = serializers.ChoiceField(choices=UserModel.CHOICES, required=False, default='user')

    # 仅在序列化中使用，用于注册成功后，返回登录令牌 ；toekn  refresh
    token = serializers.CharField(read_only=True)
    refresh = serializers.CharField(read_only=True)

    class Meta():
        model = UserModel
        fields = ['email', 'role', 'password', 're_password', 'token', 'refresh']
        extra_kwargs = {
            "email":{
                "required":True,
                "write_only":True,
            },
            "password":{
                "required": True,
                "write_only": True,
                "min_length":6,
                "max_length":16
            }
        }
    def validate(self, attrs):
        # 自定义任意校验规则
        # 校验传递数据，是否满足业务需求
        email = attrs.get('email',None)
        # 判断邮箱是否满足规则
        if not re.match(r'/^\S+@\S+\.\S+$/',email):
            raise serializers.ValidationError(detail="邮箱格式错误",code="email")
        print('-------邮箱校验通过--------')

        # 校验两次密码是否相同
        password = attrs.get('password')
        re_password = attrs.get('re_password')

        if password != re_password:
            raise serializers.ValidationError(detail="两次密码不一致,请重新输入密码",code="password")

        print('-------密码校验通过,两次密码相同---------')

        # ------------------- 初判断用户是否存在 ------------------

        # 程序健壮性考虑
        # 判断一次用户是否存在
        try:
            UserModel.objects.get(email__exact=email)
            raise serializers.ValidationError(detail='用户已经存在了...请登录',code='email')
        except UserModel.DoesNotExist:
            print('注册信息,不存在于数据,可以正常执行注册操作.所有数据校验通过')

        # 校验通过，删除不必要得字段
        attrs.pop('re_password')
        return attrs

    def create(self, validated_data):
        email = validated_data.get('email')
        password = validated_data.get('password')
        # 注册新用户，初始化用户信息
        users = UserModel.objects.create_user(
            email = email,
            password= password,
            role = validated_data.get('role', 'user'),
            # 随机给默认用户名 ,根据需求随机生成
            username= email,
            avatar = "avatar/2024/avatar.jpg"
        )
        # 返回数据
        # token   refresh
        print('------用户创建成功,手动签发token----------')
        # 手动签发token
        refresh = CoustomTokenObtainPairSerializer.get_token(user=users)

        users.refresh = str(refresh)
        users.token = str(refresh.access_token)

        return users

# ============================================ 短信登录 ============================================

class SmsLoginSerializer(serializers.Serializer):
    phone = serializers.CharField(max_length=11, min_length=11, required=True)
    code = serializers.CharField(max_length=6, min_length=6, required=True)

    def validate(self, attrs):
        phone = attrs.get('phone')
        code = attrs.get('code')

        # 判断手机号是否合法
        if not re.match(r'^1[3456789]\d{9}$', phone):
            raise serializers.ValidationError(detail='手机号不合法', code='phone')

        # -------------------redis:短信验证码------------------
        redis = get_redis_connection('sms_code')
        sms_code = redis.get(f'sms_{phone}')
        # redis中获取到的数据类型都是字节类型
        if sms_code is None:
            raise serializers.ValidationError(detail='验证码过期,请重新获取验证码', code="sms_code")
        # if sms_code.decode() != code:
        if code != sms_code:
            raise serializers.ValidationError(detail='验证码错误,请重新输入', code='sms_code')

        redis.delete(f'sms_{phone}')
        # -------------------redis:短信验证码------------------

        # 程序健壮性考虑
        # 判断用户是否存在
        try:
            UserModel.objects.get(phone__exact=phone)
        except UserModel.DoesNotExist:
            raise serializers.ValidationError(detail='用户不存在...请注册', code='phone')

        # 手动签发token
        users = UserModel.objects.get(phone__exact=phone)
        refresh = TokenObtainPairSerializer.get_token(users)
        users.refresh = str(refresh['refresh'])
        users.token = str(refresh['access'])

        return attrs

    def create(self, validated_data):
        # 由于我们已经在validate中处理了用户验证和token签发，这里不需要重复操作
        return validated_data

# ============================================ 密码登录 ============================================

class PasswordLoginSerializer(serializers.Serializer):
    username = serializers.CharField(required=False)
    phone = serializers.CharField(max_length=11, min_length=11, required=False)
    email = serializers.EmailField(required=False)
    password = serializers.CharField(required=True)
    re_password = serializers.CharField(required=True, write_only=True)

    class Meta():
        model = UserModel
        fields = ['username', 'phone', 'email', 'password', 're_password', 'token', 'refresh']

    def validate(self, attrs):
        username = attrs.get('username')
        phone = attrs.get('phone')
        email = attrs.get('email')
        password = attrs.get('password')
        re_password = attrs.get('re_password')

        # 校验两次密码是否相同
        if password != re_password:
            raise serializers.ValidationError(detail="两次密码不一致,请重新输入密码", code="password")

        # 使用Q对象来组合查询条件
        from django.db.models import Q
        try:
            user = UserModel.objects.get(Q(username__exact=username) | Q(phone__exact=phone) | Q(email__exact=email))
        except UserModel.DoesNotExist:
            raise serializers.ValidationError(detail='用户名不存在', code='username')

        # 校验密码
        if not user.check_password(password):
            raise serializers.ValidationError(detail='密码错误', code='password')

        # 手动签发token
        refresh = TokenObtainPairSerializer.get_token(user)
        user.refresh = str(refresh['refresh'])
        user.token = str(refresh['access'])

        # 校验通过，删除不必要得字段
        attrs.pop('re_password')

        return attrs

    def create(self, validated_data):
        # 由于我们已经在validate中处理了用户验证和token签发，这里不需要重复操作
        return validated_data
